{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "值类别与相关概念概览\n",
    "\n",
    "| 概念                                           | 关键特性                                            | 与其他概念的关系                                             | 典型用法                                             |\n",
    "| ---------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------- |\n",
    "| **左值（Lvalue）**                             | 拥有持久存储、可取地址、有标识；可复用              | 只能绑定到左值引用；传递给万能引用时需要引用折叠保持左值属性 | 变量、数组元素、函数返回左值引用等                   |\n",
    "| **右值（Rvalue）**                             | 临时对象/即将被销毁；不可直接取地址                 | 能绑定到右值引用；可被移动；完美转发需通过 `std::forward` 恢复为右值 | 字面量、返回值为非引用的函数结果、`std::move` 产物等 |\n",
    "| **左值引用（Lvalue Reference）**               | 形如 `T&`；只能绑定到左值                           | 在模板中与引用折叠配合：`T& &`、`T& &&` 均折叠为 `T&`        | 函数参数、别名、延长对象生命周期                     |\n",
    "| **右值引用（Rvalue Reference）**               | 形如 `T&&`；绑定到右值（非模板场景）                | 搭配移动构造/移动赋值；与引用折叠规则形成 `T&& &` → `T&`     | 移动语义、实现资源所有权转移                         |\n",
    "| **引用折叠（Reference Collapsing）**           | 模板推导时对 `T&`、`T&&` 组合自动化简               | 规则：`&` + `&` → `&`; `&` + `&&` → `&`; `&&` + `&` → `&`; `&&` + `&&` → `&&` | 保证万能引用推导结果正确；支撑完美转发               |\n",
    "| **万能引用（Universal/Forwarding Reference）** | 形如模板参数 `T&&`，但当 `T` 需要推导时可接收左右值 | 实际值类别依赖引用折叠：传入左值 → `T&`, 参数变为 `T&`; 传入右值 → `T`, 参数保持 `T&&` | 泛型函数、容器构造、转发包装器                       |\n",
    "| **完美转发（Perfect Forwarding）**             | 借助 `std::forward<T>` 让参数值类别不变地传递       | 要求参数是万能引用；`std::forward` 内部利用引用折叠恢复原始左右值属性 | 封装构造、工厂函数、回调包装等                       |\n",
    "\n",
    "关系与逻辑梳理\n",
    "\n",
    "1. **左值/右值** 是最基础的值类别划分：决定对象的生命周期、能否取地址、是否适合移动。\n",
    "2. **左值引用** 和 **右值引用** 分别绑定左值与右值，提供了资源复用（左值）与移动（右值）的语义基础。\n",
    "3. **引用折叠** 是模板推导的“规则表”，决定了混合引用类型最终会被折叠成什么形态，避免了手动区分复杂组合。\n",
    "4. **万能引用** 本质是“待推导的 `T&&`”，通过引用折叠根据实参值类别自动变成左值引用或右值引用，从而实现统一接口。\n",
    "5. **完美转发** 借助 `std::forward` 和万能引用，将接收到的参数原样转发，既保留左值的可复用性，也保留右值的可移动性。\n",
    "\n",
    "这些概念如同一个链条：值类别 → 引用 → 引用折叠 → 万能引用 → 完美转发，逐层构建出现代 C++ 模板与泛型编程中高效、安全的参数传递机制。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 左值（lvalue）与右值（rvalue）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 名称              | 含义                               | 特征                           | 示例                       |\n",
    "| ----------------- | ---------------------------------- | ------------------------------ | -------------------------- |\n",
    "| **左值 (lvalue)** | 可持久存在的对象，有明确的内存地址 | 可以取地址、可出现在赋值号左边 | `int x; x = 3;` 中的 `x`   |\n",
    "| **右值 (rvalue)** | 临时值、不可取地址的纯右值和将亡值 | 通常无法取地址、生命周期短     | 字面量 `3`，表达式 `x + 1` |\n",
    "\n",
    "C++11 起，右值细分为：\n",
    "\n",
    "- **纯右值 (prvalue)**：字面量、临时对象等。\n",
    "- **将亡值 (xvalue)**：即将被移动、资源可被“窃取”的对象，例如 `std::move(x)` 的结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "#include <utility>\n",
    "\n",
    "// 区分左值、右值的函数重载\n",
    "void classify(const int& value) {\n",
    "    std::cout << \"classify(const int&): 绑定到左值，值 = \" << value << '\\n';\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "左值与右值示例\n",
      "\n",
      "classify(const int&): 绑定到左值，值 = 42\n",
      "classify(int&&): 绑定到右值，值 = 7\n",
      "classify(int&&): 绑定到右值，值 = 43\n",
      "classify(int&&): 绑定到右值，值 = 42\n",
      "\n",
      "对比 std::move 前后 x 的值仍然存在：x = 42\n"
     ]
    }
   ],
   "source": [
    "void classify(int&& value) {\n",
    "    std::cout << \"classify(int&&): 绑定到右值，值 = \" << value << '\\n';\n",
    "}\n",
    "\n",
    "{\n",
    "    std::cout << \"左值与右值示例\\n\\n\";\n",
    "\n",
    "    int x = 42;                 // x 是左值\n",
    "    classify(x);                // 触发 const int& 重载\n",
    "\n",
    "    classify(7);                // 7 是纯右值 (prvalue)，触发 int&& 重载\n",
    "\n",
    "    classify(x + 1);            // 表达式结果是纯右值\n",
    "\n",
    "    classify(std::move(x));     // std::move(x) 是将亡值 (xvalue)，触发 int&& 重载\n",
    "\n",
    "    std::cout << \"\\n对比 std::move 前后 x 的值仍然存在：x = \" << x << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 引用：左值引用与右值引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 类型         | 声明形式 | 绑定对象                       | 示例                                    |\n",
    "| ------------ | -------- | ------------------------------ | --------------------------------------- |\n",
    "| **左值引用** | `T&`     | 只能绑定左值                   | `int a = 1; int& ref = a;`              |\n",
    "| **右值引用** | `T&&`    | 只能绑定右值（纯右值或将亡值） | `int&& r = 2; auto&& u = std::move(a);` |\n",
    "\n",
    "右值引用的意义在于：\n",
    "\n",
    "- 区分“可被移动”的对象。\n",
    "- 与移动语义、完美转发等结合。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "引用基本用法示例\n",
      "\n",
      "通过左值引用修改前 value = 10\n",
      "通过左值引用修改后 value = 20\n",
      "右值引用初始化 rref = 30\n",
      "修改右值引用后 rref = 35\n",
      "经过 std::move 后 value 的内容仍可访问 value = 99\n",
      "右值引用 moved = 99\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <utility>\n",
    "\n",
    "{\n",
    "    std::cout << \"引用基本用法示例\\n\\n\";\n",
    "\n",
    "    int value = 10;\n",
    "\n",
    "    int& lref = value;          // 左值引用，必须绑定到左值\n",
    "    std::cout << \"通过左值引用修改前 value = \" << value << '\\n';\n",
    "    lref = 20;\n",
    "    std::cout << \"通过左值引用修改后 value = \" << value << '\\n';\n",
    "\n",
    "    int&& rref = 30;            // 右值引用只能绑定右值\n",
    "    std::cout << \"右值引用初始化 rref = \" << rref << '\\n';\n",
    "    rref += 5;                  // 可以像普通变量一样使用\n",
    "    std::cout << \"修改右值引用后 rref = \" << rref << '\\n';\n",
    "\n",
    "    // std::move 把 value 强制转换为将亡值，可与右值引用绑定\n",
    "    int&& moved = std::move(value);\n",
    "    moved = 99;\n",
    "    std::cout << \"经过 std::move 后 value 的内容仍可访问 value = \" << value << '\\n';\n",
    "    std::cout << \"右值引用 moved = \" << moved << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 引用折叠（Reference Collapsing）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 C++ 的模板推导或 `auto` 推导过程中，类型参数 `T` 可能已经带有引用修饰符。如果此时我们再在外层附加 `&` 或 `&&`，就会形成“引用的引用”。语法上引用的引用是非法的，为了保持推导过程的合理性，标准规定：**在类型推导中一旦出现多重引用，就会自动折叠成单一引用类型**，这就是引用折叠（Reference Collapsing）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 引用折叠是模板与 `auto` 推导中不可避免的技术细节，确保类型组合合法且语义自然。\n",
    "- 规则非常简单：**只要出现左值引用，最终就是左值引用；纯右值引用叠加保持右值引用**。\n",
    "- 它让 C++ 模板能够“透明地”保留值类别，支撑万能引用和完美转发等关键特性。\n",
    "\n",
    "理解折叠发生的时机、动机及结果，能帮助我们写出行为可预测的泛型代码，并消除对引用推导的困惑。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**为什么会出现“引用的引用”**\n",
    "\n",
    "- **模板参数替换**：当我们写 `template <typename T> void func(T&&);`，传入一个左值时，`T` 推导为 `U&`，于是函数形参类型就变成了 `U& &&`。\n",
    "- **`auto` 推导**：`auto&& x = expr;`，如果 `expr` 是左值，`auto` 推导为 `U&`，于是 `auto&&` 实际上是 `U& &&`。\n",
    "- **`typedef`/`using` 组合**：`using LRef = int&; LRef& x = n;` —— 这里 `LRef&` 形成了 `int& &`。\n",
    "- **`decltype` 表达式**：`decltype((var))` 会得到左值引用类型，如果在模板里再套叠，就会形成组合引用。\n",
    "\n",
    "为了让这些场景合法并具有一致含义，C++11 引入了引用折叠规则。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**折叠规则背后的直观理解**\n",
    "\n",
    "规则总结为：**如果组合中出现左值引用，则最终类型是左值引用；否则在全是右值引用时保持右值引用**。\n",
    "\n",
    "通俗理解：\n",
    "- 左值引用（`&`）更“粘”，一旦混入，最终就以左值引用收场。\n",
    "- 只有纯右值引用（`&&`）叠加时，才保持右值属性。\n",
    "\n",
    "这与 C++ 对引用“必须有明确目标”的设计相符：左值引用保证绑定到持久对象，而右值引用强调临时对象，可被移动。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 表达式   | 折叠结果 | 说明                                                         |\n",
    "| -------- | -------- | ------------------------------------------------------------ |\n",
    "| `T& &`   | `T&`     | 外层想再对左值引用取左值引用，最终仍是左值引用。             |\n",
    "| `T& &&`  | `T&`     | 左值引用与右值引用组合，因为出现左值引用，结果折叠为左值引用。 |\n",
    "| `T&& &`  | `T&`     | 右值引用再取左值引用，左值引用的优先级更高，结果是左值引用。 |\n",
    "| `T&& &&` | `T&&`    | 两个右值引用组合保持右值性质，结果仍是右值引用。             |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**逐步推导示例**\n",
    "\n",
    "以下用模板函数来展示折叠过程："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "template <typename T>\n",
    "void inspect(T&& param);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 调用方式                         | `T` 的推导结果 | 形参类型 `T&&`  | 折叠后形参类型 |\n",
    "| -------------------------------- | -------------- | --------------- | -------------- |\n",
    "| `inspect(x);`                    | `int&`         | `int& &&`       | `int&`         |\n",
    "| `inspect(std::move(x));`         | `int`          | `int&&`         | `int&&`        |\n",
    "| `inspect(42);`                   | `int`          | `int&&`         | `int&&`        |\n",
    "| `const int cx = 0; inspect(cx);` | `const int&`   | `const int& &&` | `const int&`   |\n",
    "\n",
    "- 当传入左值或左值引用时，`T` 自身含有 `&`，折叠结果是左值引用。\n",
    "- 传入右值时，`T` 为纯类型，形参保持右值引用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`auto` 中的引用折叠**\n",
    "\n",
    "`auto` 同样遵循这些规则："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "int value = 5;\n",
    "\n",
    "auto&& ref1 = value;      // auto 推导为 int&，ref1 类型折叠为 int&\n",
    "auto&& ref2 = 10;         // auto 推导为 int，ref2 类型为 int&&"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `ref1` 最终是左值引用，绑定到 `value`。\n",
    "- `ref2` 是右值引用，绑定到临时值 `10`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`typedef` / `using` 的折叠**\n",
    "\n",
    "类型别名不会立即折叠，只有在再次形成引用上下文时才执行折叠："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "using LRef = int&;\n",
    "using RRef = int&&;\n",
    "\n",
    "int n = 42;\n",
    "\n",
    "LRef& lr = n;   // LRef& -> int& & -> 折叠为 int&\n",
    "RRef&& rr = 0;  // RRef&& -> int&& && -> 折叠为 int&&"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`decltype` 与折叠**\n",
    "\n",
    "`decltype` 会保留表达式的值类别：\n",
    "\n",
    "- `decltype(expr)` —— 如果 `expr` 是左值，结果是左值引用类型。\n",
    "- `decltype((var))` —— 注意双括号，始终是左值引用。\n",
    "\n",
    "在模板中使用 `decltype` 时，也可能构成多重引用，需要依赖折叠："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "template <typename T>\n",
    "auto forward_like(T&& ref) -> decltype(std::forward<T>(ref)) {\n",
    "    return std::forward<T>(ref);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果 `T` 推导为 `int&`，那么 `std::forward<T>(ref)` 的返回类型是 `int& &&`，折叠为 `int&`；如果 `T` 是 `int`，返回类型为 `int&&`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**与万能引用、完美转发的关系**\n",
    "\n",
    "- 万能引用 (`T&&`) 的“万能”正是依靠引用折叠：左值传入时折叠成 `T&`，右值传入时保持 `T&&`。\n",
    "- `std::forward<T>` 内部利用 `static_cast<T&&>`，也需要折叠来确保返回正确引用类别。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 引用折叠效果演示\n",
    "\n",
    "#include <iostream>\n",
    "#include <type_traits>\n",
    "\n",
    "// 帮助函数：打印引用类型特性\n",
    "template <typename T>\n",
    "void print_reference_traits(const char* name) {\n",
    "    std::cout << name << \":\\n\";\n",
    "    std::cout << \"  is_lvalue_reference  = \"\n",
    "              << std::boolalpha << std::is_lvalue_reference<T>::value << '\\n';\n",
    "    std::cout << \"  is_rvalue_reference  = \"\n",
    "              << std::boolalpha << std::is_rvalue_reference<T>::value << '\\n';\n",
    "    std::cout << \"  is_reference         = \"\n",
    "              << std::boolalpha << std::is_reference<T>::value << \"\\n\\n\";\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 模板函数：通过万能引用观察折叠结果\n",
    "template <typename T>\n",
    "void inspect(T&& param) {\n",
    "    print_reference_traits<T>(\"  推导的 T\");\n",
    "    print_reference_traits<decltype(param)>(\"  param 的类型 (经过折叠)\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "引用折叠示例\n",
      "\n",
      "传入左值 int:\n",
      "  推导的 T:\n",
      "  is_lvalue_reference  = true\n",
      "  is_rvalue_reference  = false\n",
      "  is_reference         = true\n",
      "\n",
      "  param 的类型 (经过折叠):\n",
      "  is_lvalue_reference  = true\n",
      "  is_rvalue_reference  = false\n",
      "  is_reference         = true\n",
      "\n"
     ]
    }
   ],
   "source": [
    "std::cout << \"引用折叠示例\\n\\n\";\n",
    "\n",
    "int x = 0;\n",
    "const int cx = 0;\n",
    "\n",
    "std::cout << \"传入左值 int:\\n\";\n",
    "inspect(x);          // T 推导为 int&，param 类型为 int&"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "传入右值 int:\n",
      "  推导的 T:\n",
      "  is_lvalue_reference  = false\n",
      "  is_rvalue_reference  = false\n",
      "  is_reference         = false\n",
      "\n",
      "  param 的类型 (经过折叠):\n",
      "  is_lvalue_reference  = false\n",
      "  is_rvalue_reference  = true\n",
      "  is_reference         = true\n",
      "\n"
     ]
    }
   ],
   "source": [
    "std::cout << \"传入右值 int:\\n\";\n",
    "inspect(42);         // T 推导为 int，param 类型为 int&&"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "传入 const 左值 int:\n",
      "  推导的 T:\n",
      "  is_lvalue_reference  = true\n",
      "  is_rvalue_reference  = false\n",
      "  is_reference         = true\n",
      "\n",
      "  param 的类型 (经过折叠):\n",
      "  is_lvalue_reference  = true\n",
      "  is_rvalue_reference  = false\n",
      "  is_reference         = true\n",
      "\n"
     ]
    }
   ],
   "source": [
    "std::cout << \"传入 const 左值 int:\\n\";\n",
    "inspect(cx);         // T 推导为 const int&，param 类型为 const int&"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "传入 std::move(x):\n",
      "  推导的 T:\n",
      "  is_lvalue_reference  = false\n",
      "  is_rvalue_reference  = false\n",
      "  is_reference         = false\n",
      "\n",
      "  param 的类型 (经过折叠):\n",
      "  is_lvalue_reference  = false\n",
      "  is_rvalue_reference  = true\n",
      "  is_reference         = true\n",
      "\n"
     ]
    }
   ],
   "source": [
    "std::cout << \"传入 std::move(x):\\n\";\n",
    "inspect(std::move(x)); // T 推导为 int，param 类型为 int&&"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 万能引用（Universal Reference）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Scott Meyers 提出的术语，用于描述在以下场景出现的 `T&&`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "template <typename T>\n",
    "void func(T&& param);   // param 是万能引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "条件：\n",
    "\n",
    "1. `T` 是模板参数。\n",
    "2. `param` 是推导上下文中出现的 `T&&`。\n",
    "\n",
    "特点：\n",
    "\n",
    "- 当传入左值时：`T` 推导为 `U&`，经引用折叠，`param` 类型为 `U&`。\n",
    "- 当传入右值时：`T` 推导为 `U`，`param` 类型为 `U&&`。\n",
    "\n",
    "因此 `param` 能同时绑定左值和右值，称为**万能引用**。\n",
    "\n",
    "> 注意：`auto&& var = expr;` 中的 `auto&&` 也是万能引用，因为 `auto` 类似模板参数。\n",
    "\n",
    "相反，如果 `T` 不参与推导（如 `void func(const T&& param);` 或 `void f(std::vector<int>&& v);`），那就是纯右值引用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 万能引用在函数与 auto 推导中的表现\n",
    "\n",
    "#include <iostream>\n",
    "#include <utility>\n",
    "\n",
    "template <typename T>\n",
    "void universal_capture(T&& arg) {\n",
    "    // 判断 arg 是左值还是右值\n",
    "    if constexpr (std::is_lvalue_reference_v<T>) {\n",
    "        std::cout << \"universal_capture 捕获到左值引用\\n\";\n",
    "    } else {\n",
    "        std::cout << \"universal_capture 捕获到右值\\n\";\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 使用 auto&& 实现万能引用\n",
    "void auto_forward_demo() {\n",
    "    std::cout << \"\\nauto&& 推导示例\\n\";\n",
    "\n",
    "    int x = 100;\n",
    "    auto&& ref1 = x;            // ref1 是 int&，绑定到左值\n",
    "    std::cout << \"ref1 引用左值 x，ref1 = \" << ref1 << '\\n';\n",
    "\n",
    "    auto&& ref2 = 200;          // ref2 是 int&&，绑定到右值\n",
    "    std::cout << \"ref2 引用右值 200，ref2 = \" << ref2 << '\\n';\n",
    "\n",
    "    ref1 += 1;\n",
    "    std::cout << \"修改 ref1 后 x = \" << x << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "万能引用示例\n",
      "\n",
      "传递左值给万能引用函数:\n",
      "universal_capture 捕获到左值引用\n",
      "传递右值给万能引用函数:\n",
      "universal_capture 捕获到右值\n",
      "传递 std::move(value):\n",
      "universal_capture 捕获到右值\n",
      "\n",
      "auto&& 推导示例\n",
      "ref1 引用左值 x，ref1 = 100\n",
      "ref2 引用右值 200，ref2 = 200\n",
      "修改 ref1 后 x = 101\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    std::cout << \"万能引用示例\\n\\n\";\n",
    "\n",
    "    int value = 5;\n",
    "\n",
    "    std::cout << \"传递左值给万能引用函数:\\n\";\n",
    "    universal_capture(value);         // 推导为 T = int&\n",
    "\n",
    "    std::cout << \"传递右值给万能引用函数:\\n\";\n",
    "    universal_capture(99);            // 推导为 T = int\n",
    "\n",
    "    std::cout << \"传递 std::move(value):\\n\";\n",
    "    universal_capture(std::move(value)); // 推导为 T = int\n",
    "\n",
    "    auto_forward_demo();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 完美转发（Perfect Forwarding）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "完美转发解决的问题：模板函数捕获参数后，如何保持参数的**值类别**传递给其他函数？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "template <typename T, typename... Args>\n",
    "std::unique_ptr<T> make_unique(Args&&... args) {\n",
    "    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `Args&&` 是万能引用。\n",
    "- `std::forward<Args>(args)` 根据 `Args` 的推导结果，实现：\n",
    "  - `Args` 推导为 `U&` 时，返回 `U&`；\n",
    "  - `Args` 推导为 `U` 时，返回 `U&&`。\n",
    "- 这样 `make_unique` 内部调用 `T` 的构造函数时，能保持调用者传入参数的左值/右值属性。\n",
    "\n",
    "> 核心函数：`std::forward<T>(expr)`, 它需要 **显式模板参数**，用于判断是否应返回左值或右值引用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 完美转发构建对象并保留值类别\n",
    "\n",
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <utility>\n",
    "\n",
    "struct Gadget {\n",
    "    Gadget() {\n",
    "        std::cout << \"Gadget(): 默认构造\\n\";\n",
    "    }\n",
    "\n",
    "    Gadget(const Gadget&) {\n",
    "        std::cout << \"Gadget(const Gadget&): 拷贝构造\\n\";\n",
    "    }\n",
    "\n",
    "    Gadget(Gadget&&) noexcept {\n",
    "        std::cout << \"Gadget(Gadget&&): 移动构造\\n\";\n",
    "    }\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "\n",
    "// 工厂函数：利用完美转发透传构造参数\n",
    "template <typename T, typename... Args>\n",
    "std::unique_ptr<T> make_unique_forward(Args&&... args) {\n",
    "    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "完美转发示例\n",
      "\n",
      "1) 通过完美转发调用默认构造:\n",
      "Gadget(): 默认构造\n"
     ]
    }
   ],
   "source": [
    "std::cout << \"完美转发示例\\n\\n\";\n",
    "\n",
    "std::cout << \"1) 通过完美转发调用默认构造:\\n\";\n",
    "auto g1 = make_unique_forward<Gadget>(); // 调用 Gadget()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "2) 通过完美转发接受左值参数:\n",
      "Gadget(): 默认构造\n",
      "Gadget(const Gadget&): 拷贝构造\n"
     ]
    }
   ],
   "source": [
    "std::cout << \"\\n2) 通过完美转发接受左值参数:\\n\";\n",
    "Gadget original;\n",
    "auto g2 = make_unique_forward<Gadget>(original); // 触发拷贝构造"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "3) 通过完美转发接受右值参数:\n",
      "Gadget(): 默认构造\n",
      "Gadget(Gadget&&): 移动构造\n"
     ]
    }
   ],
   "source": [
    "std::cout << \"\\n3) 通过完美转发接受右值参数:\\n\";\n",
    "auto g3 = make_unique_forward<Gadget>(Gadget{}); // 触发移动构造"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "4) 通过 std::move(original) 保留将亡值语义:\n",
      "Gadget(Gadget&&): 移动构造\n"
     ]
    }
   ],
   "source": [
    "std::cout << \"\\n4) 通过 std::move(original) 保留将亡值语义:\\n\";\n",
    "auto g4 = make_unique_forward<Gadget>(std::move(original)); // 触发移动构造"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "vscode": {
     "languageId": "shellscript"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "完美转发示例\n",
      "\n",
      "1) 通过完美转发调用默认构造:\n",
      "Gadget(): 默认构造\n",
      "\n",
      "2) 通过完美转发接受左值参数:\n",
      "Gadget(): 默认构造\n",
      "Gadget(const Gadget&): 拷贝构造\n",
      "\n",
      "3) 通过完美转发接受右值参数:\n",
      "Gadget(): 默认构造\n",
      "Gadget(Gadget&&): 移动构造\n",
      "\n",
      "4) 通过 std::move(original) 保留将亡值语义:\n",
      "Gadget(Gadget&&): 移动构造\n"
     ]
    }
   ],
   "source": [
    "! g++ -O3 forward.cpp -o forward && ./forward"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 常见陷阱与建议"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**不要对万能引用参数使用无条件 `std::move`**：会把传入的左值也转换成右值，破坏语义。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "template <typename T>\n",
    "void bad(T&& arg) {\n",
    "    process(std::move(arg)); // 左值被意外当作右值\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**在返回值时谨慎使用 `std::move`**：\n",
    "\n",
    "- 若返回局部对象，可以 `return obj;`（编译器会应用 NRVO 或移动）。\n",
    "- 若 `return std::move(obj);`，即使捕获的变量是左值也会被移动，可能导致拷贝被阻断。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**区分万能引用与纯右值引用**："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "template <typename T>\n",
    "void f(T&&);      // 万能引用\n",
    "\n",
    "void g(std::string&&); // 纯右值引用，只接受右值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**完美转发通常与 `std::forward` 成对出现**。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "C++17",
   "version": "17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
